package tools

import (
	"flag"
	"log"

	"github.com/nacos-group/nacos-sdk-go/common/constant"
	"go.uber.org/zap"
	"google.golang.org/grpc"
)

/*
 +----------------------------------------------------------------------
 + Title        : 初始化项目
 + Author       : huwl
 + Version      : 1.0.0
 + Initial-Time : 2020-01-06
 + Last-time    : 这个文件最后修改的时间 + 修改人的名称
 + Desc         : 初始化项目
 +----------------------------------------------------------------------
*/

// 运行环境
var Env string

// Bug模式
var BugMode string

// 服务名称
var ServiceName string

// 服务版本
var ServiceVersion string

// 服务地址
var ServiceHost string

// 服务端口
var ServicePort int

// http服务地址
var HttpHost string

// http服务端口
var HttpPort int

// 上传图片域名
var UploadImageDomain string

// ++++++++++++++++++++++ 服务注册与发现、配置中心开始 ++++++++++++++++++
// 服务发现
var ServiceDiscovery string

// 服务注册
var ServiceRegister string

// 配置中心
var ConfigCenter string

// nacos 配置
type NacosConfig struct {
	Addrs               string
	NameSpaceId         string
	Username            string
	Password            string
	TimeoutMs           int
	NotLoadCacheAtAtart bool
	LogDir              string
	CacheDir            string
	LogLevel            string
	ContextPath         string
	Group               string
	ClusterName         string
}

// nacos 配置实例
var NacosCfg NacosConfig

// nacos 客户配置
var NacosClientConfig constant.ClientConfig

// nacos 服务配置
var NacosServerConfigs []constant.ServerConfig

// nacos group
var nacosGroup string

// consul服务
var ConsulService *ConsulServiceRegister

// ++++++++++++++++++++++ 服务注册与发现、配置中心结束 ++++++++++++++++++

// ++++++++++++++++++++++      DTM 配置开始       ++++++++++++++++++++++
// dtm grpc 服务地址
var DtmGrpcServer string

// dtm http 服务地址
var DtmHttpServer string

// dtm jrpc 服务地址
var DtmJgrpcServer string

// http 服务
var HttpServiceUrl string

// ++++++++++++++++++++++      DTM 配置结束       ++++++++++++++++++++++

// ++++++++++++++++++++++	Zap 日志相关参数开始   +++++++++++++++++++++
var ZapLoggerMaxSize int
var ZapLoggerMaxBackups int
var ZapLoggerMaxAge int
var ZapLoggerCompress bool
var ZapLog *zap.Logger

// ++++++++++++++++++++++	Zap 日志相关参数结束   +++++++++++++++++++++

// ++++++++++++++++++++++++++ jaeger 开始 +++++++++++++++++++++++++
var JaegerAddr string

// ++++++++++++++++++++++++++ jaeger 结束 +++++++++++++++++++++++++

// 配置中心 mysql 名称
var MySqlConfigCenter string

// 配置中心 redis 名称
var RedisConfigCenter string

// 配置中心 minio 名称
var MinioConfigCenter string

// 配置中心 mongo 名称
var MongoConfigCenter string

// 配置中心 es 名称
var EsConfigCenter string

// 配置中心 oss 名称
var OssConfigCenter string

// 配置中心 rabbit 名称
var RabbitConfigCenter string

// ---------------------- 微服务开始 ----------------------
// 用户微服务
var UesrMicroService string
var UesrMicroServiceTag string

// 公共微服务
var CommonMicroService string
var CommonMicroServiceTag string

// 账户微服务
var AccountMicroService string
var AccountMicroServiceTag string

// 用户微服务客户端连接
var UserServiceClientConn *grpc.ClientConn

// 公共微服务客户端连接
var CommonServiceClientConn *grpc.ClientConn

// 账户微服务客户端连接
var AccountServiceClientConn *grpc.ClientConn

// ---------------------- 微服务结束 ----------------------

func init() {

	// 设置日志标志：添加 Llongfile 或 Lshortfile
	log.SetFlags(log.LstdFlags | log.Llongfile) // 完整路径
	// 或者
	// log.SetFlags(log.LstdFlags | log.Lshortfile) // 短路径

	appConfig, err := GetConfig("app", "yml")
	if err != nil {
		log.Fatalf("Failed to read app config: %v", err)
	}

	// 运行环境
	flag.StringVar(&Env, "env", "dev", "运行环境")
	flag.Parse()

	log.Println("current environment: ", Env)

	// Bug模式
	BugMode = appConfig.GetString("bug_mode")

	// 获取服务名称
	ServiceName = appConfig.GetString("service_name")

	// 获取服务版本
	ServiceVersion = appConfig.GetString("service_version")

	// 获取服务地址
	ServiceHost = appConfig.GetString(Env + ".service_host")

	// 获取服务端口
	ServicePort = appConfig.GetInt(Env + ".service_port")

	// 获取http服务地址
	HttpHost = appConfig.GetString(Env + ".http_host")

	// 获取http服务端口
	HttpPort = appConfig.GetInt(Env + ".http_port")

	// 服务注册
	ServiceRegister = appConfig.GetString(Env + ".service_register")

	// 服务发现
	ServiceDiscovery = appConfig.GetString(Env + ".service_discovery")

	// 配置中心
	ConfigCenter = appConfig.GetString(Env + ".config_center")

	// 配置中心 mysql 名称
	MySqlConfigCenter = appConfig.GetString("mysql_config_center")

	// 配置中心 redis 名称
	RedisConfigCenter = appConfig.GetString("redis_config_center")

	// 配置中心 minio 名称
	MinioConfigCenter = appConfig.GetString("minio_config_center")

	// 配置中心 mongo 名称
	MongoConfigCenter = appConfig.GetString("mongo_config_center")

	// 配置中心 es 名称
	EsConfigCenter = appConfig.GetString("es_config_center")

	// 配置中心 oss 名称
	OssConfigCenter = appConfig.GetString("oss_config_center")

	// 配置中心 rabbit 名称
	RabbitConfigCenter = appConfig.GetString("rabbit_config_center")

	// ------------------ 设置微服务全局变量开始 ------------------
	// 用户微服务
	UesrMicroService = appConfig.GetString("user_micro_service")
	// 使用 consul 的时候需要tag
	UesrMicroServiceTag = appConfig.GetString("user_micro_service_tag")

	// 公共微服务
	CommonMicroService = appConfig.GetString("common_micro_service")
	// 使用 consul 的时候需要tag
	CommonMicroServiceTag = appConfig.GetString("common_micro_service_tag")

	// 公共微服务
	AccountMicroService = appConfig.GetString("account_micro_service")
	// 使用 consul 的时候需要tag
	AccountMicroServiceTag = appConfig.GetString("account_micro_service_tag")

	// ------------------ 设置微服务全局变量结束 ------------------

	// --------------------------- 服务注册开始 ---------------------------
	switch ServiceRegister {
	case "nacos":
		// 初始化配置
		InitNacosConfig()

		// 初始化 naocs 服务及连接配置
		InitNacosServerAndClientConfigs(NacosCfg)

		// 创建服务注册
		sr, err := NewNacosServiceRegister()
		if err != nil {
			log.Fatalf("Failed to create NacosServiceRegister: %v", err)
		}

		// 注册服务
		_, err = sr.RegisterService(
			ServiceHost,
			uint64(ServicePort),
			ServiceName,
			NacosCfg.ClusterName,
			NacosCfg.Group)
		if err != nil {
			log.Fatalf("Failed to nacos RegisterService: %v", err)
		}

	case "consul":
		// 读取consul配置文件
		consulConf, err := GetConfig("consul", "yml")
		if err != nil {
			log.Fatalf("Failed to read consul config: %v", err)
		}

		// 创建服务注册
		ConsulService, err := NewConsulServiceRegister(
			consulConf.GetString(Env+".addrs"),
			consulConf.GetString(Env+".secret_id"),
		)
		if err != nil {
			log.Fatalf("Failed to create ServiceRegister: %v", err)
		}

		// 注册服务
		ConsulService.RegisterService(
			consulConf.GetStringSlice("tags"),
			ServiceName,
			ServiceHost,
			ServicePort,
		)

	case "etcd":
		// 读取 etcd 配置信息
		etcdConfig, err := GetConfig("etcd", "yml")
		if err != nil {
			log.Fatalf("Failed to read etcd config: %v", err)
		}

		// 拼接名称
		watchedKey := etcdConfig.GetString(Env+".service_prefix") + "/" + ServiceName
		// 创建服务注册
		sr, err := NewEtcdServiceRegister(
			etcdConfig.GetStringSlice(Env+".addrs"),
			etcdConfig.GetString(Env+".username"),
			etcdConfig.GetString(Env+".password"),
			watchedKey,
		)
		if err != nil {
			log.Fatalf("Failed to create ServiceRegister: %v", err)
		}

		sr.KeepAlive(10)
		log.Println("---------- etcd service register success ----------")
	}
	// --------------------------- 服务注册结束 ---------------------------

	// ------------------------- 读取DTM配置开始 --------------------------
	// 读取DTM配置文件
	dtmConfig, err := GetConfig("dtm", "yml")
	if err != nil {
		log.Fatalf("Failed to read app config: %v", err)
	}

	// dtm grpc 服务地址
	DtmGrpcServer = dtmConfig.GetString(Env + ".dtm_grpc_server")

	// dtm http 服务地址
	DtmHttpServer = dtmConfig.GetString(Env + ".dtm_http_server")

	// dtm jrpc 服务地址
	DtmJgrpcServer = dtmConfig.GetString(Env + ".dtm_jrpc_server")

	// http 服务
	HttpServiceUrl = dtmConfig.GetString(Env + ".http_service_url")
	// ------------------------- 读取DTM配置结束 --------------------------

	// ----------------------- zap 日志相关参数开始 -----------------------
	ZapLoggerMaxSize = appConfig.GetInt(Env + ".zlogger_maxsize")
	ZapLoggerMaxBackups = appConfig.GetInt(Env + ".zlogger_max_backups")
	ZapLoggerMaxAge = appConfig.GetInt(Env + ".zlogger_max_age")
	ZapLoggerCompress = appConfig.GetBool(Env + ".zlogger_compress")
	// ----------------------- zap 日志相关参数结束 -----------------------

	// JaegerAddr
	JaegerAddr = appConfig.GetString(Env + ".jaeger_addr")
}

// 初始化 nacos 配置
func InitNacosConfig() {
	if NacosCfg.Addrs == "" {
		// 读取nacos配置文件
		cfg, err := GetConfig("nacos", "yml")
		if err != nil {
			log.Fatalf("Failed to read nacos config: %v", err)
		}

		NacosCfg.Addrs = cfg.GetString(Env + ".addrs")
		NacosCfg.NameSpaceId = cfg.GetString(Env + ".name_space_id")
		NacosCfg.Username = cfg.GetString(Env + ".username")
		NacosCfg.Password = cfg.GetString(Env + ".password")
		NacosCfg.TimeoutMs = cfg.GetInt(Env + ".timeout_ms")
		NacosCfg.NotLoadCacheAtAtart = cfg.GetBool(Env + ".not_load_cache_at_start")
		NacosCfg.LogDir = cfg.GetString(Env + ".log_dir")
		NacosCfg.CacheDir = cfg.GetString(Env + ".cache_dir")
		NacosCfg.LogLevel = cfg.GetString(Env + ".log_level")
		NacosCfg.ContextPath = cfg.GetString(Env + ".context_path")
		NacosCfg.Group = cfg.GetString(Env + ".group")
		NacosCfg.ClusterName = cfg.GetString(Env + ".cluster_name")
	}
}

/**
 * 初始化配置中心
 *
 * @param string configName -----------------------------------必传
 * @param any ConfigStruct ------------------------------------必传
 * @author huwl
 */
func InitConfigCenter(configName string, ConfigStruct any) {
	switch ConfigCenter {
	case "nacos":
		// 初始化配置
		InitNacosConfig()

		// 初始化 naocs 服务及连接配置
		InitNacosServerAndClientConfigs(NacosCfg)

		// 创建NACOS配置中心
		cc, err := NewNacosConfigCenter()
		if err != nil {
			log.Fatalf("Failed to create NacosConfigCenter: %v", err)
		}

		// 获取配置数据
		cc.GetConfigData(configName, ConfigStruct, "DEFAULT_GROUP")

	case "consul":
		// 读取CONSUL配置文件
		consulConf, err := GetConfig("consul", "yml")
		if err != nil {
			log.Fatalf("Failed to read consul config: %v", err)
		}

		// 创建CONSUL配置中心
		// 获取配置信息：key格式Env+"/"+configName => /micro/config/dev/mysql_config
		cc, err := NewConsulConfigCenter(
			consulConf.GetString(Env+".addrs"),
			consulConf.GetString(Env+".token"),
			consulConf.GetString(Env+".prefix")+"/"+configName,
		)
		if err != nil {
			log.Fatalf("Failed to read consul config: %v", err)
		}

		// 获取ETCD配置数据
		cc.GetConfigData(ConfigStruct)

	case "etcd":
		// 读取ETCD配置文件
		etcdConfig, err := GetConfig("etcd", "yml")
		if err != nil {
			log.Fatalf("Failed to read etcd config: %v", err)
		}

		// 创建ETCD配置中心
		cc, err := NewEtcdConfigCenter(
			etcdConfig.GetStringSlice(Env+".addrs"),
			etcdConfig.GetString(Env+".username"),
			etcdConfig.GetString(Env+".password"),
			etcdConfig.GetString(Env+".config_prefix")+"/"+configName,
		)
		if err != nil {
			log.Fatalf("Failed to create EtcdConfigCenter: %v", err)
		}

		// 获取ETCD配置数据
		cc.GetConfigData(ConfigStruct)

		// 监控ETCD配置
		cc.WatchConfig(configName, ConfigStruct)
	}
}
